:src/views/HomeFirst/FirstView.vue
<template>
  <div class="dashboard-container">
    <!-- 顶部概览卡片 -->
    <el-row :gutter="20">
      <el-col :span="6">
        <el-card shadow="hover" class="metric-card">
          <div class="card-content">
            <div class="metric-value">{{ deviceStats.totalDevices }}</div>
            <div class="metric-label">设备总数</div>
            <i class="el-icon-s-platform card-icon"></i>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card shadow="hover" class="metric-card">
          <div class="card-content">
            <div class="metric-value">{{ deviceStats.normalDevices }}</div>
            <div class="metric-label">正常运行</div>
            <i class="el-icon-success card-icon success"></i>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card shadow="hover" class="metric-card">
          <div class="card-content">
            <div class="metric-value">{{ deviceStats.abnormalDevices }}</div>
            <div class="metric-label">异常设备</div>
            <i class="el-icon-warning card-icon warning"></i>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card shadow="hover" class="metric-card">
          <div class="card-content">
            <div class="metric-value">{{ energyStats.totalPower }} kWh</div>
            <div class="metric-label">总发电量</div>
            <i class="el-icon-lightning card-icon primary"></i>
          </div>
        </el-card>
      </el-col>
    </el-row>

    <!-- 图表区域 -->
    <el-row :gutter="20" style="margin-top: 20px;">
      <!-- 设备状态分布 -->
      <el-col :span="12">
        <el-card shadow="hover" header="设备状态分布" v-loading="loading">
          <pie-chart
              v-if="chartDataReady"
              :data="deviceStatusChartData"
              height="300px"
          />
        </el-card>
      </el-col>

      <!-- 设备类型分布 -->
      <el-col :span="12">
        <el-card shadow="hover" header="设备类型分布" v-loading="loading">
          <pie-chart
              v-if="chartDataReady"
              :data="deviceTypeChartData"
              height="300px"
          />
        </el-card>
      </el-col>
    </el-row>

    <!-- 区域指标雷达图 -->
    <el-row :gutter="20" style="margin-top: 20px;">
      <el-col :span="24">
        <el-card shadow="hover" v-loading="loading">
          <template #header>
            <div class="card-header">
              <span>区域电力指标</span>
              <el-select 
                v-model="selectedRegion" 
                placeholder="请选择区域" 
                size="small" 
                style="width: 200px; margin-left: 10px;"
                @change="handleRegionChange">
                <el-option
                  v-for="item in regionList"
                  :key="item.value"
                  :label="item.label"
                  :value="item.label">
                </el-option>
              </el-select>
            </div>
          </template>
          <div id="metricRadarChart" style="height: 400px;"></div>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>

<script>
import { getRegionList, getRegionMetrics } from '@/api/region';
import { api } from '@/api';
import * as echarts from 'echarts';
import PieChart from '@/components/charts/PieChart.vue';

export default {
  name: 'FirstView',
  components: {
    PieChart,
  },
  data() {
    return {
      loading: false,
      chartDataReady: false, // 新增：图表数据就绪状态
      deviceStats: {
        totalDevices: 0,
        normalDevices: 0,
        abnormalDevices: 0
      },
      energyStats: {
        totalPower: 0,
        dailyPower: 0,
        monthlyPower: 0
      },
      deviceStatusChartData: {
        labels: ['正常设备', '异常设备'],
        datasets: [
          {
            data: [0, 0],
            backgroundColor: ['#67C23A', '#F56C6C']
          }
        ]
      },
      deviceTypeChartData: {
        labels: ['变压器', '断路器', '继电器', '电容器', '其他设备'],
        datasets: [
          {
            data: [0, 0, 0, 0, 0],
            backgroundColor: ['#409EFF', '#67C23A', '#F56C6C', '#E6A23C', '#909399']
          }
        ]
      },
      metricChart: null,
      regionList: [],         // 区域列表
      selectedRegion: null,   // 当前选中的区域
    };
  },
  async mounted() {
    // 先获取区域列表
    await this.fetchRegionList();
    // 设置默认选中第一个区域
    if (this.regionList.length > 0) {
      this.selectedRegion = this.regionList[0].label;
    }
    // 修改：先初始化图表实例
    this.initMetricChart();
    // 再加载数据
    await this.loadDashboardData();
    this.refreshTimer = setInterval(this.loadDashboardData, 30000);
  },
  methods: {
    async loadDashboardData() {
      this.loading = true;
      this.chartDataReady = false;
      try {
        // 设备统计数据
        await this.fetchDeviceStats();

        // 区域指标数据
        await this.fetchRegionMetrics();

      } catch (error) {
        console.error('加载概览数据失败:', error);
      } finally {
        this.loading = false;
      }
    },

    async fetchDeviceStats() {
      try {
        const response = await api.device.list({ page: 1, pageSize: 1000 });
        const devices = response?.data?.records || [];

        // 设备状态统计
        const [normalCount, abnormalCount] = devices.reduce((acc, cur) => {
          cur.status === 1 ? acc[0]++ : cur.status === 2 && acc[1]++;
          return acc;
        }, [0, 0]);

        this.deviceStats = {
          totalDevices: devices.length,
          normalDevices: normalCount,
          abnormalDevices: abnormalCount
        };

        this.deviceStatusChartData.datasets[0].data = [normalCount, abnormalCount];

        // 设备类型统计
        const deviceTypeCounts = [0, 0, 0, 0, 0];
        devices.forEach(device => {
          if (device.typeId >= 1 && device.typeId <= 5) {
            deviceTypeCounts[device.typeId - 1]++;
          }
        });
        this.deviceTypeChartData.datasets[0].data = deviceTypeCounts;
        
        // 标记图表数据已就绪
        this.chartDataReady = true;
        
      } catch (error) {
        console.error('获取设备统计数据失败:', error);
      }
    },

    // 获取区域列表
    async fetchRegionList() {
      try {
        const response = await getRegionList();
        this.regionList = response?.data?.map(region => ({
          label: region.label,
          value: region.label
        })) || [];
      } catch (error) {
        console.error('获取区域列表失败:', error);
      }
    },
    
    // 区域变更处理
    handleRegionChange() {
      this.fetchRegionMetrics();
    },

    async fetchRegionMetrics() {
      try {
        if (!this.selectedRegion) return;
        
        const metricsRes = await getRegionMetrics(this.selectedRegion);
        const metrics = metricsRes?.data || {};

        this.energyStats = {
          totalPower: metrics.totalPower || 0,
          dailyPower: metrics.dailyPower || 0,
          monthlyPower: metrics.monthlyPower || 0
        };

        // 更新雷达图
        this.updateMetricChart(metrics);
        // 确保图表重绘
        if (this.metricChart) {
          this.metricChart.resize();
        }
      } catch (error) {
        console.error('获取区域指标数据失败:', error);
      }
    },

    initMetricChart() {
      // 销毁旧实例避免重复创建
      if (this.metricChart) {
        this.metricChart.dispose();
        this.metricChart = null;
      }

      const radarDom = document.getElementById('metricRadarChart');
      if (!radarDom) {
        // 添加错误处理
        console.error('雷达图容器未找到');
        return;
      }

      this.metricChart = echarts.init(radarDom);
      const metricLabels = {
        voltage: '电压 (V)',
        current: '电流 (A)',
        activePower: '有功功率 (kW)',
        reactivePower: '无功功率 (kVar)',
        temperature: '设备温度 (°C)',
        dailyPower: '日用电量 (kWh)',
        monthlyPower: '月用电量 (kWh)',
        totalPower: '累计发电量 (kWh)'
      };

      // 动态计算每个指标的最大值
      const maxValues = {
        voltage: 300, // 根据实际情况调整
        current: 20,
        activePower: 200,
        reactivePower: 100,
        temperature: 100,
        dailyPower: 200,
        monthlyPower: 5000,
        totalPower: 200000
      };

      const radarOption = {
        tooltip: { trigger: 'item' },
        legend: { top: 10 },
        radar: {
          center: ['50%', '55%'],
          radius: '60%',
          indicator: Object.keys(metricLabels).map(key => ({
            name: metricLabels[key],
            max: maxValues[key] // 使用动态计算的最大值
          })),
          splitArea: { show: true }
        },
        series: [ {
          type: 'radar',
          data: [ {
            value: [],
            name: '区域指标'
          }],
          itemStyle: { color: '#409EFF' },
          areaStyle: { color: 'rgba(64, 158, 255, 0.2)' }
        }]
      };

      this.metricChart.setOption(radarOption);

      // 响应式调整
      const resizeObserver = new ResizeObserver(() => {
        this.metricChart.resize();
      });
      resizeObserver.observe(radarDom);
    },

    updateMetricChart(metrics) {
      if (!this.metricChart) return;

      const metricKeys = [
        'voltage', 'current', 'activePower', 'reactivePower',
        'temperature', 'dailyPower', 'monthlyPower', 'totalPower'
      ];

      const values = metricKeys.map(key => metrics[key] || 0);

      this.metricChart.setOption({
        series: [{
          data: [{
            value: values
          }]
        }]
      });
    }
  }
};
</script>

<style scoped>
.dashboard-container {
  padding: 20px;
  background-color: #f5f7fa;
}

.metric-card {
  margin-bottom: 20px;
  border-radius: 8px;
  border: none;
  transition: transform 0.3s;
}

.metric-card:hover {
  transform: translateY(-5px);
}

.card-content {
  position: relative;
  padding: 20px;
}

.metric-value {
  font-size: 24px;
  font-weight: bold;
  color: #303133;
}

.metric-label {
  font-size: 14px;
  color: #909399;
  margin-top: 5px;
}

.card-icon {
  position: absolute;
  right: 20px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 40px;
  opacity: 0.2;
}

.card-icon.success {
  color: #67C23A;
}

.card-icon.warning {
  color: #F56C6C;
}

.card-icon.primary {
  color: #409EFF;
}

/* 新增区域选择头部样式 */
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
</style>
